package cn.core.kpis.service;

import cn.core.kpis.eo.*;
import cn.core.kpis.mapper.*;
import cn.core.kpis.qo.*;
import cn.core.kpis.vo.ComputeTaskVO;
import cn.core.tool.ao.DataExportAO;
import cn.core.tool.exception.CoreException;
import cn.core.tool.service.CoreService;
import cn.core.tool.service.FileService;
import cn.core.tool.util.CoreTool;
import cn.core.tool.util.Paging;
import cn.core.tool.util.Param;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.googlecode.aviator.AviatorEvaluatorInstance;
import lombok.extern.log4j.Log4j2;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;

/**
 * 计算任务 服务
 */
@Log4j2
@Service
public class ComputeTaskService {

  @Resource
  private ApplicationEventPublisher applicationEventPublisher;

  @Resource
  private FileService fileService;

  @Resource
  private CoreService coreService;

  @Resource
  private AviatorEvaluatorInstance aviatorEvaluatorInstance;

  @Resource
  private ComputeTaskMapper computeTaskMapper;

  @Resource
  private TaskParamMapper taskParamMapper;

  @Resource
  private TaskExpressionMapper taskExpressionMapper;

  @Resource
  private TaskExpressionParamMapper taskExpressionParamMapper;

  @Resource
  private ExpressionMapper expressionMapper;

  @Resource
  private ExpressionParamMapper expressionParamMapper;

  @Resource
  private TaskExpressionSqlParamMapper taskExpressionSqlParamMapper;

  @Resource
  private SqlStrMapper sqlStrMapper;

  @Resource
  private ExpressionOutputMapper expressionOutputMapper;

  /**
   * 计算任务 >>> 保存
   */
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
  public ComputeTask save(ComputeTask eo) throws Exception {
    try {
      if (CoreTool.isNullEo(eo)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      eo.setId(CoreTool.getUUID32());
      computeTaskMapper.save(eo);
      return eo;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 批量保存
   */
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
  public Collection<ComputeTask> saveBatch(Collection<ComputeTask> eos) throws Exception {
    try {
      if (CoreTool.isEmpty(eos)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      for (ComputeTask eo : eos) {
        if (CoreTool.isNullEo(eo)) {
          throw new CoreException(CoreException.E_PARAM_ERR);
        }
        eo.setId(CoreTool.getUUID32());
      }
      computeTaskMapper.saveBatch(new Paging<>(), eos);
      return eos;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 修改
   */
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
  public ComputeTask update(ComputeTask eo) throws Exception {
    try {
      if (CoreTool.isNullEo(eo) || CoreTool.isNullStr(eo.getId())) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      ComputeTask oeo = computeTaskMapper.pk(new ComputeTaskQO().setId(eo.getId()));
      if (CoreTool.isNullEo(oeo)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
//      if (eo.getVersions() != null ? !eo.getVersions().equals(oeo.getVersions()) : oeo.getVersions() != null ? true : false) {
//        throw new CoreException(CoreException.E_VERSIONS_ERR);
//      }
      computeTaskMapper.update(eo);
      return eo;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 批量修改
   */
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
  public Collection<ComputeTask> updateBatch(Collection<ComputeTask> eos) throws Exception {
    try {
      if (CoreTool.isEmpty(eos)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      for (ComputeTask eo : eos) {
        if (CoreTool.isNullEo(eo) || CoreTool.isNullStr(eo.getId())) {
          throw new CoreException(CoreException.E_PARAM_ERR);
        }
        ComputeTask oeo = computeTaskMapper.pk(new ComputeTaskQO().setId(eo.getId()));
        if (CoreTool.isNullEo(oeo)) {
          throw new CoreException(CoreException.E_PARAM_ERR);
        }
//        if (eo.getVersions() != null ? !eo.getVersions().equals(oeo.getVersions()) : oeo.getVersions() != null ? true : false) {
//          throw new CoreException(CoreException.E_VERSIONS_ERR);
//        }
      }
      computeTaskMapper.updateBatch(new Paging<>(), eos);
      return eos;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 删除
   */
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
  public void remove(ComputeTask eo) throws Exception {
    try {
      if (CoreTool.isNullEo(eo) || CoreTool.isNullStr(eo.getId())) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      computeTaskMapper.remove(eo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 批量删除
   */
  @Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = Exception.class)
  public void removeBatch(Collection<ComputeTask> eos) throws Exception {
    try {
      if (CoreTool.isEmpty(eos)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      for (ComputeTask eo : eos) {
        if (CoreTool.isNullEo(eo) || CoreTool.isNullStr(eo.getId())) {
          throw new CoreException(CoreException.E_PARAM_ERR);
        }
      }
      computeTaskMapper.removeBatch(eos);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 数据量
   */
  public Long count(ComputeTaskQO qo) throws Exception {
    try {
      return computeTaskMapper.count(qo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 主键查询
   */
  public ComputeTask pk(ComputeTaskQO qo) throws Exception {
    try {
      if (CoreTool.isNullEo(qo) || CoreTool.isNullStr(qo.getId())) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      return computeTaskMapper.pk(qo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 查询
   */
  public Collection<ComputeTask> query(ComputeTaskQO qo) throws Exception {
    try {
      return computeTaskMapper.query(qo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 分页
   */
  public Paging<ComputeTask> paging(Param<ComputeTaskQO> param) throws Exception {
    try {
      if (CoreTool.isNullEo(param)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      if (param.getPage() < 1 || param.getRows() < 1) {
        throw new CoreException(CoreException.E_PAGING_PARAM_ERR);
      }
      Paging<ComputeTask> paging = new Paging<>(param);
      if (CoreTool.isEmpty(param.getData()) || CoreTool.isNullEo(param.get())) {
        Long count = computeTaskMapper.count(null);
        paging.setCount(count);
        if (count > 0) {
          if (count <= paging.getOffset()) {
            throw new CoreException(CoreException.E_PAGING_PARAM_ERR);
          }
          paging.setData(computeTaskMapper.paging(paging, null));
        }
      } else {
        Long count = computeTaskMapper.count(param.get());
        paging.setCount(count);
        if (count > 0) {
          if (count <= paging.getOffset()) {
            throw new CoreException(CoreException.E_PAGING_PARAM_ERR);
          }
          paging.setData(computeTaskMapper.paging(paging, param.get()));
        }
      }
      return paging;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 业务数据量
   */
  public Long countVo(ComputeTaskQO qo) throws Exception {
    try {
      return computeTaskMapper.countVo(qo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 业务主键查询
   */
  public ComputeTaskVO pkVo(ComputeTaskQO qo) throws Exception {
    try {
      if (CoreTool.isNullEo(qo) || CoreTool.isNullStr(qo.getId())) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      return computeTaskMapper.pkVo(qo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 业务查询
   */
  public Collection<ComputeTaskVO> queryVo(ComputeTaskQO qo) throws Exception {
    try {
      return computeTaskMapper.queryVo(qo);
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 业务分页
   */
  public Paging<ComputeTaskVO> pagingVo(Param<ComputeTaskQO> param) throws Exception {
    try {
      if (CoreTool.isNullEo(param)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      if (param.getPage() < 1 || param.getRows() < 1) {
        throw new CoreException(CoreException.E_PAGING_PARAM_ERR);
      }
      Paging<ComputeTaskVO> paging = new Paging<>(param);
      if (CoreTool.isEmpty(param.getData()) || CoreTool.isNullEo(param.get())) {
        Long count = computeTaskMapper.countVo(null);
        paging.setCount(count);
        if (count > 0) {
          if (count <= paging.getOffset()) {
            throw new CoreException(CoreException.E_PAGING_PARAM_ERR);
          }
          paging.setData(computeTaskMapper.pagingVo(paging, null));
        }
      } else {
        Long count = computeTaskMapper.countVo(param.get());
        paging.setCount(count);
        if (count > 0) {
          if (count <= paging.getOffset()) {
            throw new CoreException(CoreException.E_PAGING_PARAM_ERR);
          }
          paging.setData(computeTaskMapper.pagingVo(paging, param.get()));
        }
      }
      return paging;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 数据导入
   */
  public Collection<ComputeTask> dataImport(String ao) throws Exception {
    try {
      if (CoreTool.isNullStr(ao)) {
        throw new CoreException(CoreException.E_DATA_IMPORT_FILE_URL_IS_NULL_ERR);
      }
      List<ComputeTask> allData = null;
      try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(fileService.getFileStreamByFileUrl(ao))) {
        ExcelReader reader = ExcelUtil.getReader(byteArrayInputStream);
        reader.addHeaderAlias("任务名称", "taskName");
        reader.addHeaderAlias("分类", "taskType");
        reader.addHeaderAlias("描述", "description");
        reader.addHeaderAlias("排序权重", "weightOrder");
        allData = reader.readAll(ComputeTask.class);
        if (CoreTool.isEmpty(allData)) {
          throw new CoreException(CoreException.E_IMPORT_DATA_IS_NULL_ERR);
        }
//        CoreDataEvent typeCoreDataEvent = new CoreDataEvent("getDictNameValueMapInfoByDictKey", "type");
//        applicationEventPublisher.publishEvent(typeCoreDataEvent);
//        LinkedHashMap<String, String> typeDictNameValueMapInfo = CoreTool.isNotNullStr(typeCoreDataEvent.getData()) ? typeCoreDataEvent.getData(new TypeToken<LinkedHashMap<String, String>>(){}) : new LinkedHashMap<String, String>();
        for (ComputeTask eo : allData) {
          eo.setId(CoreTool.getUUID32());
//          eo.setType(typeDictNameValueMapInfo.get(eo.getType()));
        }
        computeTaskMapper.saveBatch(new Paging<>(), allData);
      } catch (IOException e) {
        throw new CoreException(CoreException.E_ERR);
      }
      return allData;
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务 >>> 数据导出
   */
  public String dataExport(DataExportAO<ComputeTaskQO> ao) throws Exception {
    try {
      if (CoreTool.isEmpty(ao.getDataExportFieldConf())) {
        throw new CoreException(CoreException.E_DATA_EXPORT_FIELD_CONF_IS_NULL_ERR);
      }
      Collection<ComputeTaskVO> vos = computeTaskMapper.queryVo(ao.get());
      if (CoreTool.isEmpty(vos)) {
        throw new CoreException(CoreException.E_EXPORT_DATA_IS_NULL_ERR);
      }
//      CoreDataEvent typeCoreDataEvent = new CoreDataEvent("getDictValueMapInfoByDictKey", "type");
//      applicationEventPublisher.publishEvent(typeCoreDataEvent);
//      LinkedHashMap<String, String> typeDictValueMapInfo = CoreTool.isNotNullStr(typeCoreDataEvent.getData()) ? typeCoreDataEvent.getData(new TypeToken<LinkedHashMap<String, String>>(){}) : new LinkedHashMap<String, String>();
//      for (ComputeTaskVO eo : vos) {
//        eo.setType(typeDictValueMapInfo.get(eo.getType()));
//      }
      return fileService.getFileUrlByDataExportAO(new DataExportAO<ComputeTaskVO>()
          .setBigDataExport(ao.getBigDataExport())
          .setFileModule(ao.getFileModule())
          .setFileName(ao.getFileName())
          .setDataExportFieldConf(ao.getDataExportFieldConf())
          .setData(vos));
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

  /**
   * 计算任务Id >>> 计算
   */
  public void compute(String id) throws Exception {
    try {
      if (CoreTool.isNullStr(id)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      ComputeTask rComputeTask = computeTaskMapper.pk(new ComputeTaskQO().setId(id));
      if (CoreTool.isNullEo(rComputeTask)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      LinkedHashMap<String, Object> taskParamMap = new LinkedHashMap<String, Object>();
      Collection<TaskParam> rTaskParamSet = taskParamMapper.query(new TaskParamQO().setFkid(rComputeTask.getId()).setWeightOrderAsc("y"));
      if (CoreTool.isNotEmpty(rTaskParamSet)) {
        for (TaskParam eTaskParam : rTaskParamSet) {
          taskParamMap.put(eTaskParam.getParamName(), eTaskParam.getParamValue());
        }
      }
      Collection<TaskExpression> rTaskExpressionSet = taskExpressionMapper.query(new TaskExpressionQO().setFkid(rComputeTask.getId()).setWeightOrderAsc("y"));
      if (CoreTool.isEmpty(rTaskExpressionSet)) {
        throw new CoreException(CoreException.E_PARAM_ERR);
      }
      for (TaskExpression eTaskExpression : rTaskExpressionSet) {
        LinkedHashMap<String, Object> taskExpressionParamMap = new LinkedHashMap<String, Object>();
        Collection<TaskExpressionParam> rTaskExpressionParamSet = taskExpressionParamMapper.query(new TaskExpressionParamQO().setFkid(eTaskExpression.getId()).setWeightOrderAsc("y"));
        if (CoreTool.isNotEmpty(rTaskExpressionParamSet)) {
          for (TaskExpressionParam eTaskExpressionParam : rTaskExpressionParamSet) {
            taskExpressionParamMap.put(eTaskExpressionParam.getParamName(), eTaskExpressionParam.getParamValue());
          }
        }
        Expression rExpression = expressionMapper.pk(new ExpressionQO().setId(eTaskExpression.getExpressionId()));
        if (CoreTool.isNullEo(rExpression)) {
          throw new CoreException(CoreException.E_PARAM_ERR);
        }
        Collection<ExpressionParam> rExpressionParamSet = expressionParamMapper.query(new ExpressionParamQO().setFkid(rExpression.getId()).setWeightOrderAsc("y"));
        if (CoreTool.isEmpty(rExpressionParamSet)) {
          throw new CoreException(CoreException.E_PARAM_ERR);
        }
        LinkedHashMap<String, Object> expressionParamMap = new LinkedHashMap<String, Object>();
        for (ExpressionParam eExpressionParam : rExpressionParamSet) {
          LinkedHashMap<String, Object> taskExpressionSqlParamMap = new LinkedHashMap<String, Object>();
          Collection<TaskExpressionSqlParam> rTaskExpressionSqlParamSet = taskExpressionSqlParamMapper.query(new TaskExpressionSqlParamQO().setFkid(eTaskExpression.getId()).setExpressionParamId(eExpressionParam.getId()).setWeightOrderAsc("y"));
          if (CoreTool.isNotEmpty(rTaskExpressionSqlParamSet)) {
            for (TaskExpressionSqlParam eTaskExpressionSqlParam : rTaskExpressionSqlParamSet) {
              taskExpressionSqlParamMap.put(eTaskExpressionSqlParam.getParamName(), eTaskExpressionSqlParam.getParamValue());
            }
          }
          LinkedHashMap<String, Object> sqlParamMap = new LinkedHashMap<String, Object>();
          sqlParamMap.putAll(taskParamMap);
          sqlParamMap.putAll(taskExpressionParamMap);
          sqlParamMap.putAll(taskExpressionSqlParamMap);
          String dsName = sqlParamMap.get("dsName") != null ? sqlParamMap.get("dsName").toString() : "master";
          if ("sqlGetValue".equals(eExpressionParam.getParamType())) {
            SqlStr rSqlStr = sqlStrMapper.pk(new SqlStrQO().setId(eExpressionParam.getSqlStrId()));
            if (CoreTool.isNullEo(rSqlStr)) {
              throw new CoreException(CoreException.E_PARAM_ERR);
            }
            Object ro = coreService.execSql(dsName, rSqlStr.getSqlStr(), sqlParamMap);
            if (ro != null) {
              expressionParamMap.put(eExpressionParam.getParamName(), ro);
            } else {
              expressionParamMap.put(eExpressionParam.getParamName(), "0");
            }
          } else if ("fixedValue".equals(eExpressionParam.getParamType())) {
            expressionParamMap.put(eExpressionParam.getParamName(), sqlParamMap.get(eExpressionParam.getParamName()));
          } else {
            throw new CoreException(CoreException.E_PARAM_ERR);
          }
        }
        com.googlecode.aviator.Expression exp = aviatorEvaluatorInstance.compile(rExpression.getExpressionStr());
        HashMap<String, Object> rExpObjMap = (HashMap) exp.execute(expressionParamMap);
        Collection<ExpressionOutput> rExpressionOutputSet = expressionOutputMapper.query(new ExpressionOutputQO().setFkid(rExpression.getId()).setWeightOrderAsc("y"));
        if (CoreTool.isNotEmpty(rExpressionOutputSet)) {
          for (ExpressionOutput eExpressionOutput : rExpressionOutputSet) {
            SqlStr rSqlStr = sqlStrMapper.pk(new SqlStrQO().setId(eExpressionOutput.getSqlStrId()));
            if (CoreTool.isNullEo(rSqlStr)) {
              throw new CoreException(CoreException.E_PARAM_ERR);
            }
            String dsName = CoreTool.isNotNullStr(eExpressionOutput.getDsName()) ? eExpressionOutput.getDsName() : "master";
            coreService.execSql(dsName, rSqlStr.getSqlStr(), rExpObjMap);
          }
        }
      }
    } catch (Exception e) {
      if (log.isDebugEnabled()) {
        log.error(e.getMessage(), e);
      }
      throw e;
    }
  }

}
